#include "gui.h"
#include "ui_gui.h"

#include <QCheckBox>
#include <QLabel>

#include <QFileDialog>

gui::gui(QWidget *parent) :
	QMainWindow(parent),
	ui(new Ui::gui)
{
	server_started = false;
	log_pos = 0;
	file_lines = 0;
	file_log_name = "log4cplus_gui_log_" + QDateTime::currentDateTime().toString() + ".bin";

	ui->setupUi(this);
	connect(&n, SIGNAL(packet_full(log_event)), this, SLOT(slot_packet_full(log_event)));
	connect(&n, SIGNAL(new_client(QString)), this, SLOT(slot_new_client(QString)));
}

gui::~gui()
{
	delete ui;
}

void gui::file_append()
{
	if(file_lines < events.count())
	{
		file_log.setFileName(file_log_name);
		if(!file_log.open(QIODevice::WriteOnly | QIODevice::Append)) return;

		for(int i = file_lines; i < events.count(); i++)
		{
			QByteArray ba = events[i].to_ba();
			int sz = ba.size();
			file_log.write(net::int2ba(sz));
			file_log.write(ba);
		}

		file_lines = events.count();
		file_log.close();
	}
}

void gui::log_timeout()
{
	if(!server_started) return;
	file_append();
	if(!ui->b_pause->isChecked()) update_log();
}

void gui::slot_packet_full(log_event le)
{
	if(!le.valid) return;
	if(!clients[le.client_name]) return;
	append_log(le);
}

void gui::append_log(log_event le)
{
	events.append(le);
}

bool gui::filter_passed(log_event e)
{
	QString f_logger = ui->f_logger->text();
	if(f_logger.length())
	{
		if(!e.logger_name.contains(f_logger, Qt::CaseInsensitive)) return false;
	}

	bool eq = false;
	bool ok = false;
	QString fl = ui->f_level->text();
	if(fl.startsWith("="))
	{
		eq = true;
		fl.remove(0, 1);
	}
	int level = fl.toInt(&ok);
	if(ok)
	{
		if(eq)
		{
			if((e.log_level / 10000) != level) return false;
		}
		else
		{
			if((e.log_level / 10000) < level) return false;
		}
	}

	QString f_msg1 = ui->f_msg1->text();
	if(f_msg1.length())
	{
		if(!e.message.contains(f_msg1, Qt::CaseInsensitive)) return false;
	}
	QString f_msg2 = ui->f_msg2->text();
	if(f_msg2.length())
	{
		if(!e.message.contains(f_msg2, Qt::CaseInsensitive)) return false;
	}
	QString f_msg3 = ui->f_msg3->text();
	if(f_msg3.length())
	{
		if(!e.message.contains(f_msg3, Qt::CaseInsensitive)) return false;
	}

//	qDebug() << "f_logger=" << f_logger << "level=" << level << "msg=" << f_msg1 << f_msg2 << f_msg3;
	return true;
}

void gui::update_log()
{
	QTime t;
	t.start();
	QString log;
	if(!events.count()) return;

	if(!ui->b_pause->isChecked())
	{
		log_pos = events.count() - 1;
	}

	int log_max_lines = GUI_MAX_LINES;
	if(ui->log_max_lines->text().length())
	{
		bool ok = false;
		int lml = ui->log_max_lines->text().toInt(&ok);
		if(ok) log_max_lines = lml;
	}

	int msg_width = 75;
	QString msg_w = ui->msg_width->text();
	if(msg_w.length())
	{
		bool ok = false;
		int mw = msg_w.toInt(&ok);
		if(ok) msg_width = mw;
	}

	int n = 0;
	int count = 0;
	int off = log_pos;
	while((count < log_max_lines) && (off >= 0))
	{
		log_event e = events[off];
		bool en = true;
		if(server_started) en = clients[e.client_name];
		if((!e.valid) || (!en) || (!filter_passed(e)))
		{
			off--;
			n++;
			continue;
		}

		log = log_form(off, e, msg_width) + '\n' + log;

		off--;
		count++;
		n++;
	}

	ui->log->clear();
	ui->log->appendPlainText(log);

	qDebug() << "gui::update_log" << t.elapsed() << "ms" << events.count();
}

QString gui::log_form(int index, log_event e, int msg_width)
{
	QString ls;
	if(ui->c_n->isChecked()) ls += QString::number(index).leftJustified(12, QChar(' '), true) + " ";
	if(ui->c_time->isChecked()) ls += e.str_current_time.leftJustified(28, QChar(' '), true) + " ";
	if(ui->c_client->isChecked()) ls += e.client_name.leftJustified(20, QChar(' '), true) + " ";

	int level = e.log_level / 10000;
	ls += "L" + QString::number(level).leftJustified(2, QChar(' '), true) + " ";
	ls += e.logger_name.leftJustified(12, QChar(' '), true) + ": ";

	ls += e.message.leftJustified(msg_width, QChar(' '));
	if(ui->c_ffl->isChecked()) ls += + " -> " + e.func + "@" + QString::number(e.line) + ":" + e.file;

	return ls;
}

void gui::slot_new_client(QString client_name)
{
	QCheckBox *cb = new QCheckBox(this);
	QLabel *la = new QLabel(this);
	la->setText(client_name);
	cb->setUserData(0, (QObjectUserData*)la);
	cb->setChecked(true);

	connect(cb, SIGNAL(clicked(bool)), this, SLOT(clients_filter(bool)));

	ui->hb_clients->insertWidget(0, la);
	ui->hb_clients->insertWidget(0, cb);
	clients[client_name] = true;
}

void gui::clients_filter(bool on1off0)
{
	QCheckBox *cb = (QCheckBox*)sender();
	if(!cb) return;

	QLabel *la = (QLabel*)cb->userData(0);
	if(la)
	{
		QString client_name = la->text();
		clients[client_name] = on1off0;
		qDebug() << "filter" << client_name << "active=" << on1off0;
		update_log();
	}
}

void gui::on_b_clear_clicked()
{
	ui->log->clear();
}

void gui::on_c_n_clicked()
{
	update_log();
}

void gui::on_c_client_clicked()
{
	update_log();
}

void gui::on_c_time_clicked()
{
	update_log();
}

void gui::on_c_ffl_clicked()
{
	update_log();
}

void gui::on_f_update_clicked()
{
	update_log();
}

bool gui::load_log(QString fn)
{
	qDebug() << "gui::load_log filename=" << fn;

	file_log.setFileName(fn);
	if(file_log.open(QIODevice::ReadOnly))
	{
		while(!file_log.atEnd())
		{
			int sz = net::ba2int(file_log.read(4), 0);
			if(sz)
			{
				QByteArray ba = file_log.read(sz);
				log_event le;
				le.from_ba(ba);
				if(!le.valid)
				{
					setWindowTitle("ERROR: file, bad data");
					break;
				}
				events.append(le);
			}
			else
			{
				setWindowTitle("ERROR: file, wrong size");
				break;
			}
		}

		file_log.close();
		setWindowTitle("FILE: " + fn);
		ui->log_max_lines->setText(QString::number(events.count()));
		log_pos = events.count() - 1;
		update_log();
		return true;
	}

	return false;
}

void gui::on_b_load_clicked()
{
	// load from file

	events.clear();
	log_pos = 0;

	QFileDialog fd;
	if(fd.exec())
	{
		QStringList sf = fd.selectedFiles();
		if(!sf.length()) return;

		if(!load_log(sf[0])) return;

		ui->b_host->setEnabled(false);
		ui->b_pause->setEnabled(false);
	}
}

void gui::on_b_host_clicked()
{
	// host server
	bool ok = false;
	int port = ui->host_port->text().toInt(&ok);
	if(!ok) return;

	n.start_server(port);
	ui->b_host->setEnabled(false);
	ui->b_load->setEnabled(false);
	connect(&log_timer, SIGNAL(timeout()), this, SLOT(log_timeout()));

	setWindowTitle("SERVER: port " + QString::number(port));
	server_started = true;

	log_timer.start(2500);
}
